<template>
  <div class="app-container">
    <div class="market_header">
      <el-form
        ref="searchForm"
        size="small"
        :inline="true"
        :model="searchForm"
        :rules="rules"
        label-width="80px"
      >
        <div class="drawer__content_rule clearfix">
          <span class="el-form-item__label">营销名称</span>
          <el-form-item prop="name">
            <el-input
              v-model="searchForm.name"
              :disabled="!notWatch"
              clearable
              placeholder="营销任务名称"
            />
          </el-form-item>
        </div>
        <div class="drawer__content_rule clearfix">
          <span class="el-form-item__label">营销代码</span>
          <el-form-item prop="code">
            <el-input
              v-model="searchForm.code"
              :disabled="disabledCode"
              clearable
              placeholder="营销任务代码"
            />
          </el-form-item>
        </div>
      </el-form>
      <div>
        <el-button
          type="text"
          icon="el-icon-delete"
          size="large"
          :disabled="delBtnDisabled"
          @click="deleteElement"
        ></el-button>
        <el-button
          type="primary"
          size="mini"
          @click="changeLineStyle"
        >
          {{ lineStyle === "Bezier" ? "直线" : "曲线" }}
        </el-button>

        <el-button
          v-show="notWatch"
          type="primary"
          size="mini"
          @click="saveInfo"
        >保存</el-button>
        <el-button
          type="primary"
          size="mini"
          @click="goBack"
        >返回</el-button>
      </div>
    </div>
    <!-- jsplumb 区域 -->
    <div
      v-if="easyFlowVisible"
      v-loading="saveLoading"
      class="jsplumb"
    >
      <div style="width: 230px;border-right: 1px solid #dce3e8;">
        <node-menu
          ref="nodeMenu"
          @addNode="addNode"
        ></node-menu>
      </div>
      <div
        id="efContainer"
        ref="efContainer"
        v-flowDrag
        class="container"
      >
        <template v-for="node in data.nodeList">
          <flow-node
            :id="node.id"
            :key="node.id"
            :node="node"
            :active-element="activeElement"
            @changeNodeSite="changeNodeSite"
            @clickNode="clickNode"
            @dblclickNode="dblclickNode"
          >
          </flow-node>
        </template>
        <!-- 给画布一个默认的宽度和高度 -->
        <div style="position:absolute;top: 2000px;left: 2000px;">
          <span style="visibility:hidden">1</span>
        </div>
      </div>
    </div>
    <!-- 组件区域 -->
    <flow-node-copy
      :visible.sync='copyVisible'
      :data='data'
      :jsPlumb='jsPlumb'
      :node='comNodeObj'
      ref="copyForm"
      :form-setting="formSetting"
      @repaintEverything="repaintEverything"
      @reloadCanvas="reloadCanvas"
    ></flow-node-copy>
    <flow-node-timer
      :visible.sync='timerVisible'
      :data='data'
      :jsPlumb='jsPlumb'
      :node='comNodeObj'
      ref="timerForm"
      :form-setting="formSetting"
      @repaintEverything="repaintEverything"
      @reloadCanvas="reloadCanvas"
    ></flow-node-timer>
    <flow-node-random
      :visible.sync='randomVisible'
      :data='data'
      :jsPlumb='jsPlumb'
      :node='comNodeObj'
      ref="randomForm"
      :form-setting="formSetting"
      @repaintEverything="repaintEverything"
      @reloadCanvas="reloadCanvas"
    ></flow-node-random>
    <flow-node-wx
      :visible.sync='wxVisible'
      :data='data'
      :jsPlumb='jsPlumb'
      :node='comNodeObj'
      ref="wxForm"
      :form-setting="formSetting"
      @repaintEverything="repaintEverything"
    ></flow-node-wx>
    <flow-node-start
      :visible.sync='startVisible'
      :data='data'
      :jsPlumb='jsPlumb'
      :node='comNodeObj'
      ref="startForm"
      :form-setting="formSetting"
      @repaintEverything="repaintEverything"
    ></flow-node-start>
    <flow-node-tenant
      :visible.sync='tenantVisible'
      :data='data'
      :jsPlumb='jsPlumb'
      :node='comNodeObj'
      ref="tenantForm"
      :form-setting="formSetting"
      @reloadCanvas="reloadCanvas"
      @repaintEverything="repaintEverything"
    ></flow-node-tenant>
    <flow-node-message
      :visible.sync='messageVisible'
      :data='data'
      :jsPlumb='jsPlumb'
      :node='comNodeObj'
      ref="messageForm"
      :form-setting="formSetting"
      @repaintEverything="repaintEverything"
    ></flow-node-message>
    <flow-node-wait
      :visible.sync='waitVisible'
      :data='data'
      :jsPlumb='jsPlumb'
      :node='comNodeObj'
      ref="waitForm"
      :form-setting="formSetting"
      @repaintEverything="repaintEverything"
    ></flow-node-wait>
    <flow-node-exclusion
      ref="exclusionForm"
      :visible.sync='exclusionVisible'
      :data='data'
      :jsPlumb='jsPlumb'
      :node='comNodeObj'
      :form-setting="formSetting"
      @repaintEverything="repaintEverything"
      @reloadCanvas="reloadCanvas"
    ></flow-node-exclusion>
  </div>
</template>
<script>
import { easyFlowMixin } from "./component/mixins";
import { commonMixin } from "./component/common-mixin";
import flowNode from "./component/node";
import nodeMenu from "./component/node_menu";
import lodash from "lodash";
import "./component/index.css";
// import FlowNodeForm from "./component/node_form";
import FlowNodeCopy from "./component/node_copy";
import FlowNodeTimer from "./component/node_timer";
// import FlowNodeProperty from "./component/node_property";
import FlowNodeExclusion from './component/node_exclusion'
import FlowNodeRandom from "./component/node_random";
import FlowNodeWx from "./component/node_wx";
import FlowNodeStart from "./component/node_start";
import FlowNodeTenant from "./component/node_tenant";
import FlowNodeMessage from "./component/node_message";
import FlowNodeWait from "./component/node_wait";
import createEnum from "@/utils/create-enum";
const NODETYPE = createEnum({
  start: ["startEvent", "开始节点"],
  tenant: ['groupSelectorEvent', '群组节点'],
  tenantChild: ['groupSelectorEvent', '群组子节点'],
  merge: ['groupMergeEvent', '群组合并节点'],
  union: ['groupMergeEvent', '群组交集节点'],
  except: ['groupMergeEvent', '群组差集节点'],
  exclusion: ['groupDeduplicationEvent', '群组排重节点'],
  exclusionChild: ['groupDeduplicationEvent', '群组排重子节点'],
  end: ["endEvent", "结束节点"],
  wait: ["waitEvent", "等待节点"],
  message: ["smsEvent", "短信发送节点"],
  wx: ["wechatEvent", "微信发送节点"],
  copy: ["branchCopy", "复制分支"],
  copyChild: ["branchCopy", "复制子分支"],
  random: ["branchRandom", "随机分支"],
  randomChild: ["branchRandom", "随机子分支"],
  timer: ["branchTime", "时间分支"],
  timerChild: ["branchTime", "时间子分支"]
});
export default {
  components: {
    FlowNodeStart,
    FlowNodeMessage,
    FlowNodeTenant,
    // FlowNodeForm,
    FlowNodeCopy,
    FlowNodeExclusion,
    FlowNodeTimer,
    FlowNodeRandom,
    FlowNodeWx,
    FlowNodeWait,
    nodeMenu,
    flowNode
  },
  mixins: [easyFlowMixin, commonMixin],
  props: ["id"],
  data() {
    return {
      // 组件Visibles数据区域
      exclusionVisible: false,
      startVisible: false,
      tenantVisible: false,
      randomVisible: false,
      timerVisible: false,
      copyVisible: false,
      messageVisible: false,
      wxVisible: false,
      waitVisible: false,
      comNodeObj: {},
      // 组件Visibles数据区域-end
      saveLoading: false,
      lineStyle: "Strigth",
      searchForm: {
        name: "",
        code: ""
      },
      clickedBackSpace: true, // 防止多次出发Backspace事件
      // jsPlumb 实例
      jsPlumb: null,
      // 控制画布销毁
      easyFlowVisible: true,
      // 控制流程数据显示与隐藏
      flowInfoVisible: false,
      // 是否加载完毕标志位
      loadEasyFlowFinish: false,
      // 数据
      data: {
        nodeList: [],
        lineList: []
      },
      // 激活的元素、可能是节点、可能是连线
      activeElement: {
        type: undefined, // 节点type:如 start、end.
        nodeName: undefined,
        nodeType: undefined, // 可选值 node 、line
        // 节点ID
        nodeId: undefined,
        // 连线ID
        sourceId: undefined,
        targetId: undefined
      },
      panelObj: {
        nodeList: [
          {
            ico: "market-start",
            id: "start989",
            left: "40px",
            name: "开始",
            state: "success",
            top: "40px",
            type: "start"
          },
          {
            ico: "market-tenant",
            id: "tenant989",
            left: "160px",
            name: "群组",
            state: "success",
            top: "40px",
            type: "tenant"
          },
          {
            ico: "market-tenant",
            id: "tenantBranch1",
            left: "280px",
            name: "群组1",
            state: "success",
            top: "40px",
            type: "tenantChild"
          },
          {
            ico: "market-tenant",
            id: "tenantBranch2",
            left: "280px",
            name: "群组2",
            state: "success",
            top: "120px",
            type: "tenantChild"
          }
        ],
        lineList: [
          {
            from: "start989",
            to: "tenant989"
          },
          {
            from: "tenant989",
            to: 'tenantBranch1'
          },
          {
            from: "tenant989",
            to: 'tenantBranch2'
          }
        ]
      },
      formSetting: {},
      branchTypeArr: ["copy", "timer", "random", "property"], // 分支type集合
      rules: {
        name: [{ required: true, message: "请填写名称", trigger: "blur" }],
        code: [{ required: true, message: "请填写代码", trigger: "blur" }]
      }
    };
  },
  computed: {
    disabledCode() {
      const { type } = this.$route.query;
      return type === "edit" || type === "watch";
    },
    notWatch() {
      const { type } = this.$route.query;
      return type !== "watch";
    },
    // 连线样式
    connectorStyle() {
      return this.lineStyle === "Bezier"
        ? { Connector: ["Bezier", { curviness: 100 }] }
        : {
          Connector: [
            "Flowchart",
            {
              stub: 30,
              gap: 1,
              alwaysRespectStubs: false,
              midpoint: 0.5,
              cornerRadius: 10
            }
          ]
        };
    },
    delBtnDisabled() {
      const { nodeType, type, sourceId, targetId } = this.activeElement;
      const { nodeList = [] } = this.data;
      const sourceNode = nodeList.find(node => node.id === sourceId);
      const targetNode = nodeList.find(node => node.id === targetId);
      const noDeleteNodeArr = [
        "start",
        "tenant",
        "copyChild",
        "randomChild",
        "propertyChild",
        "timerChild"
      ]; // 这些节点不可以删除
      const noDeleteLine = {
        fromType: sourceNode ? sourceNode.type : "",
        targetType: targetNode ? targetNode.type : ""
      };
      const nodeCondition =
        nodeType === "node" && noDeleteNodeArr.includes(type);
      if (nodeCondition) {
        return true;
      }
      if (
        nodeType === "line" &&
        noDeleteLine["fromType"] === "start" &&
        noDeleteLine["targetType"] === "tenant"
      ) {
        return true;
      }
      if (
        nodeType === "line" &&
        `${noDeleteLine["fromType"]}Child` === noDeleteLine["targetType"]
      ) {
        return true;
      }
      return false;
    }
  },
  mounted() {
    this.jsPlumb = this.$jsPlumb.getInstance();
    if (this.id) {
      this.getSetting();
    } else {
      this.dataReload(this.panelObj);
    }
  },
  beforeMount() {
    window.addEventListener("keydown", this.keyDown);
  },
  beforeDestroy() {
    window.removeEventListener("keydown", this.keyDown);
  },
  methods: {
    reloadCanvas() {
      this.dataReload(lodash.cloneDeep(this.data), this.connectorStyle);
    },
    changeLineStyle() {
      this.lineStyle = this.lineStyle === "Bezier" ? "Strigth" : "Bezier";
      this.reloadCanvas();
    },
    keyDown(e) {
      if (e || window.e) {
        const { key, target } = e;
        const deleteKeyArr = ["Backspace", "Delete"];
        // 使用this.$el.querySelector('#efContainer')而不使用document.getElementById,是因为我们获取元素，尽量用this.$el去一级级获取，用document，单页面应用总会出些意外
        // js的contains方法用来查看dom元素的包含关系-用来限定键盘事件只局限于当前dom范围内
        const efContainerId = this.$el.querySelector("#efContainer");
        if (
          deleteKeyArr.includes(key) &&
          !this.delBtnDisabled &&
          this.clickedBackSpace &&
          target.contains(efContainerId)
        ) {
          this.deleteElement();
        }
      }
    },
    async getSetting() {
      // const { code, data } = await getMarketInfo({ id: this.id });
      // if (code === this.$httpCode.ok) {
      //   const { code, name, canvasData } = data;
      //   this.searchForm.name = name;
      //   this.searchForm.code = this.disabledCode ? code : "";
      //   const { formSetting, data: panelData } = JSON.parse(canvasData);
      //   this.formSetting = formSetting;
      //   const { nodeList, lineList } = panelData;
      //   this.panelObj.nodeList = nodeList;
      //   this.panelObj.lineList = lineList;
      //   this.dataReload(this.panelObj);
      // }
    },
    jsPlumbInit(lineStyle) {
      this.jsPlumb.ready(() => {
        // 导入默认配置
        this.jsPlumb.importDefaults({ ...this.jsplumbSetting, ...lineStyle });
        // 会使整个jsPlumb立即重绘。
        this.jsPlumb.setSuspendDrawing(false, true);
        // 初始化节点
        this.loadEasyFlow();
        // 单点击了连接线, https://www.cnblogs.com/ysx215/p/7615677.html
        this.jsPlumb.bind("click", (conn, originalEvent) => {
          console.log(originalEvent, "originalEvent");
          this.activeElement.nodeType = "line";
          this.activeElement.sourceId = conn.sourceId;
          this.activeElement.targetId = conn.targetId;
        });
        // 连线
        this.jsPlumb.bind("connection", evt => {
          const from = evt.source.id;
          const to = evt.target.id;
          if (this.loadEasyFlowFinish) {
            this.data.lineList.push({ from: from, to: to });
          }
        });

        // 删除连线回调
        this.jsPlumb.bind("connectionDetached", evt => {
          this.deleteLine(evt.sourceId, evt.targetId);
        });

        // 改变线的连接节点
        this.jsPlumb.bind("connectionMoved", evt => {
          this.changeLine(evt.originalSourceId, evt.originalTargetId);
        });

        // 连线右击
        // this.jsPlumb.bind("contextmenu", evt => {
        //   // console.log('contextmenu', evt)
        // });

        // 完成连接前 // 可绑定事件避免源和目标在同一出上
        this.jsPlumb.bind("beforeDrop", evt => {
          const from = evt.sourceId;
          const to = evt.targetId;
          if (this.loopLine(from, to)) {
            this.$message.error("连线回环");
            return false;
          }
          if (from === to) {
            this.$message.error("节点不支持连接自己");
            return false;
          }
          if (this.hasLine(from, to)) {
            this.$message.error("该关系已存在,不允许重复创建");
            return false;
          }
          if (this.hashOppositeLine(from, to)) {
            this.$message.error("不支持两个节点之间连线回环");
            return false;
          }
          this.$message.success("连接成功");
          return true;
        });

        // beforeDetach 连线分离前
        // this.jsPlumb.bind("beforeDetach", evt => {
        //   // console.log('beforeDetach', evt)
        // });
        //https://wdd.js.org/jsplumb-chinese-tutorial/#/?id=_211-%e9%99%90%e5%88%b6%e8%8a%82%e7%82%b9%e6%8b%96%e5%8a%a8%e5%8c%ba%e5%9f%9f
        // 限制节点拖动区域
        this.jsPlumb.setContainer(this.$refs.efContainer);
      });
    },
    // 加载流程图
    loadEasyFlow() {
      // 初始化节点
      for (var i = 0; i < this.data.nodeList.length; i++) {
        const node = this.data.nodeList[i];
        this.makeSourceTarget(node);
      }
      // 初始化连线
      for (let i = 0; i < this.data.lineList.length; i++) {
        const line = this.data.lineList[i];
        this.jsPlumb.connect(
          {
            source: line.from,
            target: line.to
          },
          this.jsplumbConnectOptions
        );
      }
      this.$nextTick(function () {
        this.loadEasyFlowFinish = true;
      });
    },
    // 删除激活的元素
    deleteElement() {
      const {
        type,
        nodeType,
        nodeName,
        nodeId,
        sourceId,
        targetId
      } = this.activeElement;
      this.clickedBackSpace = false;
      if (nodeType === "node") {
        this.deleteNode({ nodeName, nodeId, type });
      } else if (nodeType === "line") {
        this.$confirm("确定删除所点击的线吗?", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        })
          .then(() => {
            var conn = this.jsPlumb.getConnections({
              source: sourceId,
              target: targetId
            })[0];
            this.jsPlumb.deleteConnection(conn);
          })
          .catch(() => { })
          .finally(() => {
            this.clickedBackSpace = true;
          });
      }
    },
    // 删除线
    deleteLine(from, to) {
      this.data.lineList = this.data.lineList.filter(function (line) {
        if (line.from === from && line.to === to) {
          return false;
        }
        return true;
      });
    },
    // 改变连线
    changeLine(oldFrom, oldTo) {
      this.deleteLine(oldFrom, oldTo);
    },
    // 改变节点的位置
    changeNodeSite(data) {
      for (var i = 0; i < this.data.nodeList.length; i++) {
        const node = this.data.nodeList[i];
        if (node.id === data.nodeId) {
          node.left = data.left;
          node.top = data.top;
        }
      }
    },
    // 加载流程图
    dataReload(data, lineStyles) {
      this.easyFlowVisible = false;
      this.data.nodeList = [];
      this.data.lineList = [];
      this.$nextTick(() => {
        const clonedata = lodash.cloneDeep(data);
        this.easyFlowVisible = true;
        this.data = clonedata;
        this.$nextTick(() => {
          this.jsPlumb = this.$jsPlumb.getInstance();
          this.$nextTick(() => {
            this.jsPlumbInit(lineStyles);
          });
        });
      });
    },
    /**
     * 获取分支节点的子节点
     */
    addBranchNode(nodeMenu, { type, parentId, brandIndex, left, top }) {
      const { nodeList } = this.data;
      const nodeId = this.getUUID();
      const nodeName = this.getNodeName(nodeMenu);
      const childLeft = left + 160;
      const childTop = top + brandIndex * 80;
      const node = {
        left: `${childLeft}px`,
        top: `${childTop}px`,
        name: nodeName,
        type: `${type}Child`,
        ico: `market-${type}-child`,
        id: nodeId
      };
      nodeList.push(node);
      this.$nextTick(() => {
        this.makeSourceTarget(node);
        this.jsPlumb.connect(
          {
            source: parentId,
            target: nodeId
          },
          this.jsplumbConnectOptions
        );
      });
    },
    /**
     * 拖拽结束后添加新的节点
     * @param evt
     * @param nodeMenu 被添加的节点对象
     * @param mousePosition 鼠标拖拽结束的坐标
     */
    addNode(evt, nodeMenu, mousePosition) {
      const { nodeList } = this.data;
      const screenX = evt.originalEvent.clientX;
      const screenY = evt.originalEvent.clientY;
      const efContainer = this.$refs.efContainer; // 获取某个元素相对于视窗的位置集合
      console.log(mousePosition, "mousePosition");
      const containerRect = efContainer.getBoundingClientRect();
      let left = screenX;
      let top = screenY;
      // 计算是否拖入到容器中
      if (
        left < containerRect.x ||
        left > containerRect.width + containerRect.x ||
        top < containerRect.y ||
        top > containerRect.y + containerRect.height
      ) {
        this.$message.error("请把节点拖入到画布中");
        return;
      }
      left = left - containerRect.x + efContainer.scrollLeft;
      top = top - containerRect.y + efContainer.scrollTop;
      // 居中
      left -= 80;
      top -= 14;
      const nodeId = this.getUUID();
      const nodeName = this.getNodeName(nodeMenu);
      const { type, ico } = nodeMenu;
      const node = {
        left: `${left}px`,
        top: `${top}px`,
        state: "success",
        name: nodeName,
        type,
        ico,
        id: nodeId
      };
      nodeList.push(node);
      this.$nextTick(() => {
        this.makeSourceTarget(node);
        // https://wdd.js.org/jsplumb-chinese-tutorial/#/?id=_218-%e6%95%b4%e4%b8%aa%e8%8a%82%e7%82%b9%e4%bd%9c%e4%b8%basource%e6%88%96%e8%80%85target
        // 上方jsPlumbInit初始化时，已经给jsPlumb绑定了连接事件。
        //  this.jsPlumb.bind("connection", evt => {
        //   const from = evt.source.id;
        //   const to = evt.target.id;
        //   if (this.loadEasyFlowFinish) {
        //     this.data.lineList.push({ from: from, to: to });
        //   }
        // });
      });
      if (this.branchTypeArr.includes(type)) {
        const loopBranch = [this.addBranchNode, this.addBranchNode];
        loopBranch.forEach((fn, brandIndex) =>
          fn(nodeMenu, { parentId: nodeId, type, brandIndex, left, top })
        );
      }
    },
    /**
     * 删除节点
     * @param nodeName 被删除节点的nodeName
     */
    deleteNode({ nodeName, nodeId, type }) {
      this.$confirm(`确定要删除节点 ${nodeName}?`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
        closeOnClickModal: false
      })
        .then(() => {
          /**
           * 这里需要进行业务判断，是否可以删除
           */
          this.data.nodeList = this.data.nodeList.filter(
            ({ id }) => id !== nodeId
          );
          this.activeElement.nodeType = "";
          if (this.branchTypeArr.includes(type) || type === 'exclusion') {
            this.deleteBranchNode(nodeId);
          } else {
            this.$nextTick(() => {
              this.jsPlumb.removeAllEndpoints(nodeId);
            });
          }
        })
        .catch(() => { })
        .finally(() => {
          this.clickedBackSpace = true;
        });
      return true;
    },
    clickNode(node) {
      const { id: nodeId, name: nodeName, type } = node;
      this.activeElement.nodeType = "node";
      this.activeElement.type = type;
      this.activeElement.nodeId = nodeId;
      this.activeElement.nodeName = nodeName;
    },
    // 双击打开弹框
    dblclickNode(node) {
      const { type } = node;
      // const refNode = `${type}Form`;
      const noOpenNodeArr = ['randomChild', "tenantChild", 'merge', 'union', 'except', 'copyChild', 'propertyChild', 'timerChild', 'end']
      if (!noOpenNodeArr.includes(type)) {
        this[`${type}Visible`] = true
        this.comNodeObj = node
        // const params = { data: this.data, node, jsPlumb: this.jsPlumb };
        // this.$refs[refNode].nodeInit(params);
      }
    },
    // 连线是否回环
    loopLine(from, to) {
      // 获取要连接的所有子节点的ID
      const childIdArr = this.getChildId(to);
      const childIdArrays = [];
      const that = this;
      function childfn(childIdArr) {
        if (childIdArr.length > 0) {
          for (let i = 0; i < childIdArr.length; i++) {
            childIdArrays.push(childIdArr[i]);
            childfn(that.getChildId(childIdArr[i]));
          }
        }
      }
      childfn(childIdArr);
      if (childIdArrays.includes(from)) {
        return true;
      }
      return false;
    },
    // 是否具有该线
    hasLine(from, to) {
      for (var i = 0; i < this.data.lineList.length; i++) {
        var line = this.data.lineList[i];
        if (line.from === from && line.to === to) {
          return true;
        }
      }
      return false;
    },
    // 是否含有相反的线
    hashOppositeLine(from, to) {
      return this.hasLine(to, from);
    },
    repaintEverything() {
      // 当需要对修改过后的元素重新计算端点和连接线时，则可以使用
      this.jsPlumb.repaint();
    },
    validateSave() {
      const validateObj = { code: "ok", message: "ok" };
      const { nodeList } = this.data;
      const nodeTypeArr = nodeList.map(node => node.type);
      if (!nodeTypeArr.includes("end")) {
        return { code: "error", message: "缺少结束节点" };
      }
      for (let i = 0; i < nodeList.length; i++) {
        const { name, id, type } = nodeList[i];
        const fromSettingObj = this.formSetting[id];
        const validateNodeArr = [
          "end",
          "random",
          "timer",
          "property",
          "copy",
          "copyChild",
          "exclusion",
          "merge",
          "union",
          "except",
          "tenant"
        ];
        if (!fromSettingObj && !validateNodeArr.includes(type)) {
          return { code: "error", message: `${name}节点未配置` };
        }
      }
      return validateObj;
    },
    saveInfo() {
      this.$refs.searchForm.validate(async valid => {
        if (valid) {
          const { code: resCode, message } = this.validateSave();
          if (resCode === "error") {
            return this.$message.error(message);
          }
          const { name, code } = this.searchForm;
          const panelData = {
            data: this.data,
            formSetting: this.formSetting
          };
          const basic = {
            id: this.id && this.disabledCode ? this.id : "",
            name,
            code,
            canvasData: JSON.stringify(panelData),
            ruleJson: this.jsonData()
          };
          console.log(basic, "basic");
          // this.saveLoading = true;
          // let res = {};
          // try {
          //   // res = await saveMarket(basic);
          // } catch {
          //   this.saveLoading = false;
          // }
          // if (res.code === this.$httpCode.ok) {
          //   this.goBack();
          // }
        }
      });
    },
    jsonData() {
      const startId = this.getNodeIdByType("start");
      const tenantId = this.getNodeIdByType("tenant");
      const that = this;
      const startNode = this.getFlowNodeObj(startId);
      const childArr = this.getChildId(tenantId);
      /**
       * 递归过滤工作流，返回符合工作流运行模式的各个节点id数组
       * @param childArr 子节点
       * @param next
          * {
              id:xxxx
              name:开始
              x:120,
              y:150,
              type:xxx
              params:{}
              next:[{  }]  --递归嵌套
            }
       */
      function flowRecursion(childArr, next = []) {
        if (childArr.length > 0) {
          for (let i = 0; i < childArr.length; i++) {
            const id = childArr[i];
            const nodeObj = that.getFlowNodeObj(id);
            flowRecursion(that.getChildId(id), nodeObj.next);
            next.push(nodeObj);
          }
        }
      }
      flowRecursion(childArr, startNode.next);
      // console.log(JSON.stringify(startNode))
      return JSON.stringify(startNode);
    },
    getFlowNodeObj(id) {
      const nodeObject = this.getNodeObjById(id)
      const { name, left, top, type } = nodeObject
      const params = this.getNodeParams(id, type, name)
      // 后端需要每个节点ID不唯一，所以对于微信,短信，等待，结束这些可以有多个上流节点的节点,再手动给个随机ID
      const randomIdArr = ['wx', 'message', 'end', 'wait']
      const flowId = randomIdArr.includes(type) ? this.getUUID() : id
      const flowNodeObj = {
        id: flowId,
        name,
        x: parseInt(left),
        y: parseInt(top),
        type: NODETYPE[type],
        params,
        next: []
      }
      return flowNodeObj
    },
    // 获取节点参数
    getNodeParams(id, nodeType, nodeName) {
      let params = {};
      const nodeParams = this.formSetting[id];
      const ISPARENT = createEnum({
        PARENT: [0, "父节点"],
        CHILD: [1, "子节点"]
      });
      switch (nodeType) {
        case "start":
          var {
            taskCycle: task_cycle,
            startTime: start_time,
            endTime: end_time,
            dayNumber: day_number,
            setEachTime,
            type: dayType,
            weekDays,
            monthDays,
            yearDays: year_days
          } = nodeParams;
          var week_days = weekDays.length ? weekDays.join(",") : "";
          var month_days = monthDays.length ? monthDays.join(",") : "";
          params = {
            task_cycle,
            start_time,
            end_time,
            type: dayType,
            day_number,
            day_time: setEachTime,
            week_days,
            month_days,
            year_days,
            week_time: setEachTime,
            month_time: setEachTime,
            year_time: setEachTime
          };
          break;
        case 'tenant':
          params = {
            is_parent: ISPARENT.PARENT
          }
          break;
        case 'tenantChild':
          var { user_groupCodes } = nodeParams
          params = {
            is_parent: ISPARENT.CHILD,
            branchName: nodeName,
            branchId: id,
            groupCode: user_groupCodes
          }
          break;
        case 'merge':
          params = {
            opt_type: NODETYPE[nodeType]
          }
          break;
        case 'union':
          params = {
            opt_type: NODETYPE[nodeType]
          }
          break;
        case 'except':
          params = {
            opt_type: NODETYPE[nodeType]
          }
          break;
        case 'exclusion':
          params = {
            is_parent: ISPARENT.PARENT
          }
          break;
        case 'exclusionChild':
          var { groupNodeId, index } = nodeParams
          params = {
            is_parent: ISPARENT.CHILD,
            branchName: nodeName,
            branchId: id,
            groupNodeId,
            index
          }
          break;
        case "message":
          var {
            type: msgType,
            templateId: msgTemplateId,
            sign: msgSign,
            content: msgContent
          } = nodeParams;
          params = {
            type: msgType,
            msgSign,
            templateId: msgTemplateId,
            content: msgContent
          };
          break;
        case "wx":
          var { weChatId, templateId: wxTemplateId } = nodeParams;
          params = {
            weChatId,
            templateId: wxTemplateId
          };
          break;
        case "wait":
          var { waitType, time, dateTime } = nodeParams;
          params = {
            waitType,
            time,
            dateTime
          };
          break;
        case "timer":
          params = {
            is_parent: ISPARENT.PARENT
          };
          break;
        case "timerChild":
          var { date: timerDate } = nodeParams;
          params = {
            is_parent: ISPARENT.CHILD,
            datetime: timerDate,
            waitType: 0 // 0-指定时间；1-按小时
          };
          break;
        case "copy":
          params = {
            is_parent: ISPARENT.PARENT
          };
          break;
        case "copyChild":
          params = {
            is_parent: ISPARENT.CHILD
          };
          break;
        case "random":
          params = {
            is_parent: ISPARENT.PARENT
          };
          break;
        case "randomChild":
          var { rate } = nodeParams;
          params = {
            is_parent: ISPARENT.CHILD,
            branchName: nodeName,
            branchId: id,
            rate
          };
          break;
        default:
          params = {};
      }
      return params;
    },
    // 获取节点对象
    getNodeObjById(id) {
      const { nodeList } = this.data;
      const nodeObj = nodeList.find(node => node.id === id);
      return nodeObj || {};
    },
    // 通过节点类型获取节点ID
    getNodeIdByType(type) {
      const { nodeList } = this.data;
      const nodeObj = nodeList.find(node => node.type === type);
      return nodeObj ? nodeObj.id : "";
    },
    /**
     * 获取节点名称
     */
    getNodeName(nodeMenu) {
      const { nodeList } = this.data;
      let index = 1;
      const origName = nodeMenu.name;
      let nodeName = origName;
      while (index < 10000) {
        var repeat = false;
        for (var i = 0; i < nodeList.length; i++) {
          const node = nodeList[i];
          if (node.name === nodeName) {
            nodeName = origName + index;
            repeat = true;
          }
        }
        if (repeat) {
          index++;
          continue;
        }
        break;
      }
      return nodeName;
    },
    getNodeTypeById(id) {
      const { nodeList } = this.data;
      const node = nodeList.find(node => node.id === id);
      return node ? node.type : "";
    },
    goBack() {
      const { page, size } = this.$route.query;
      this.$router.push({
        name: "market-auto",
        params: { page, size }
      });
    }
  }
};
</script>
<style lang="scss" scoped>
// @import "../../../styles/valide-required.scss";
.drawer__content_rule {
  float: left;
}
.jsplumb {
  display: flex;
  height: calc(80vh);
  position: relative;
  width: 100%;
  ::-webkit-scrollbar {
    width: 0 !important;
  }
  -ms-overflow-style: none;
  overflow: -moz-scrollbars-none;
  #efContainer {
    background: #ebeaef;
  }
}
.market_header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  text-align: right;
  height: 48px;
  font-size: 0.88889rem;
  color: #686f79;
  margin: -1.11111rem -1.11111rem 0.83333rem;
  padding: 10px;
  border-bottom: 1px solid #ebeef5;
  span {
    font-size: 0.88889rem;
    color: #686f79;
  }
  .svg-icon {
    color: #fff;
  }
  .el-form-item {
    margin-bottom: 0;
  }
}
.demo-drawer__footer {
  text-align: center;
}
</style>
